Ce patch se base sur un patch kernel qui associe à chaque port une ACL et sur une application qui permet de mettre à jour ces ACL via un nouvel appel système.
La mise en oeuvre du patch nécessite la recompilation du noyau.
Pour appliquer le patch aux sources :
$ tar xfz linux-2.x.y.tgz $ cd linux-2.x.y $ patch -p1 < ../patch-portacl-2.x.y
port_acl_set
$ gcc -Wall -o port_acl_set port_acl_set.c
La commande port_acl_set
prend 3 paramètres :
usage : port_acl_set <+->port user
Par exemple, pour autoriser l'utilisateur franck (uid 632) à acceder au port 80 :
# ./port_acl_set +80 franck
Pour visualiser les utilisateurs ayant accès aux ports privilégiés, il faut lire le fichier /proc/net/port_acl
. On remarque que les login des utilisateurs ne sont pas donnés, seulement leur uid
:
# cat /proc/net/port_acl 80: 632
Si on souhaite enlever à l'utilisateur ayant l'uid
632 (ici franck) le droit d'acceder au port 80 :
# ./port_acl_set -80 franck
L'implémentation repose sur un principe assez simple. Le fichier source net/ipv4/af_inet.c
contient l'implémentation de l'appel système inet_bind()
qui fait appel à la fonction de contrôle capable()
pour empêcher les utilisateurs non privilégiés d'accèder à un port privilégié (<1024) :
snum = ntohs(addr->sin_port); err = -EACCES; if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) goto out;
L'implémentation de la fonction capable()
est réalisée dans plusieurs fichiers. Pour avoir un aperçu, cliquer sur
capable().
kernel/capability.c
:
int __capable(struct task_struct *t, int cap) { if (security_capable(t, cap) == 0) { t->flags |= PF_SUPERPRIV; return 1; } return 0; } EXPORT_SYMBOL(__capable); int capable(int cap) { return __capable(current, cap); } EXPORT_SYMBOL(capable);
include/linux/security.h
:
#ifdef CONFIG_SECURITY static inline int security_capable(struct task_struct *tsk, int cap) { return security_ops->capable(tsk, cap); } #else /* CONFIG_SECURITY */ static inline int security_capable(struct task_struct *tsk, int cap) { return cap_capable(tsk, cap); } #endif /* CONFIG_SECURITY */
security/commoncap.c
:
int cap_capable (struct task_struct *tsk, int cap) { /* Derived from include/linux/sched.h:capable. */ if (cap_raised(tsk->cap_effective, cap)) return 0; return -EPERM; }
include/linux/capability.h
:
#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag))
include/linux/init_task.h
:
#define INIT_TASK(tsk) \ { \ [...] .cap_effective = CAP_INIT_EFF_SET, \ .cap_inheritable = CAP_INIT_INH_SET, \ .cap_permitted = CAP_FULL_SET, \
arch/i386/kernel/init_task.c
:
/* * Initial task structure. * * All other task structs will be allocated on slabs in fork.c */ struct task_struct init_task = INIT_TASK(init_task);
Le patch ajoute la fonction port_acl()
qui retourne 1 si le user
courant a les droits d'accès au port passé en argument :
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE) && !port_acl(snum))
L'essentiel du patch implémente la mise à jour des ACL sous forme de liste chaînée.