Bug 107344

Summary: fcntl(fd, F_SETOWN, getpid()) fails with EPERM in a NPTL thread
Product: [Retired] Red Hat Linux Reporter: David Holmes <dholmes>
Component: kernelAssignee: Arjan van de Ven <arjanv>
Status: CLOSED WONTFIX QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 9CC: riel, roland, sct
Target Milestone: ---   
Target Release: ---   
Hardware: i686   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2004-09-30 15:41:36 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description David Holmes 2003-10-17 04:43:00 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030225

Description of problem:
Using RH9 out-of-the-box with the NPTL 0.34 update applied.
 
The test program tries to do fcntl(fd, F_SETOWN, getpid()) on a socket
descriptor. If it does this in the main thread then it works fine. If it does
this in a separate pthread then it fails with EPERM.
 
Looking into the bowels of sock.c sock_no_fcntl does this:
   case F_SETOWN:
        if (current->pgrp != -arg &&
            current->pid != arg &&
            !capable(CAP_KILL)) return(-EPERM);
 
Running as root provides the CAP_KILL capability and the test passes. So it
seems that there is a discrepancy between the value returned by
getpid() and the value used internally (current->pid).
 
This only fails with NPTL. If I use LD_ASSUME_KERNEL the test passes
threaded and non-threaded.

I reported this on phil_list and  Roland McGrath responded that this "is a
kernel bug that needs to be fixed in the RH backport of the NPTL support code"
and that I should file this bug report.

Version-Release number of selected component (if applicable):
kernel-2.4.20-20.9

How reproducible:
Always

Steps to Reproduce:
1. Compile the test program.

2. Run with noargs uses a non-thread version and fcntl succeeds.
3. Run with any arg a the threaded version runs and fcntl fails with EPERM.    

----- cut here for test program fcntlbug.c -----
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
 
 
#define CHECK(func, msg) \
   if ((func) != 0) { \
      fprintf(stderr, "Error: %s - %s\n", msg, strerror(errno)); \
      exit(1); \
   }
 
#define CHECKP(func) \
   do { \
    int rc = (func); \
    if (rc!= 0) { \
      fprintf(stderr, "Error: " #func " - %s\n", strerror(rc)); \
      exit(1); \
    } \
   } while(0)
 
 
int fds[] = { -1, -1 };
 
static int fcntlSetFlag(int fd,int flag) {
        int flags=fcntl(fd,F_GETFL,0);
        if (flags<0) {
                return -1;
        }
        return fcntl(fd,F_SETFL,flags|flag);
}
 
static void test() {
    int fd;
 
    CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds), "socketpair");
    fd = fds[0];
 
    if (fcntlSetFlag(fd, O_ASYNC)<0) {
        fprintf(stderr, "error setting O_ASYNC flag on %d: %s\n",
               fd, strerror(errno));
        exit(1);
    }
 
    if (fcntl(fd, F_SETOWN, getpid())<0) {
        fprintf(stderr, "error fcntl(%d, F_SETOWN, %d): %s\n",fd, getpid(),
strerror(errno));
        exit(1);
    }
     
    printf("Managed to set up socket %d ok\n", fd);
 
    close(fds[0]);
    close(fds[1]);
}
 
 
 
static void* threadRun(void* arg) {
    test();
    pthread_detach(pthread_self()); /* ensure detached to release resources */
    pthread_exit(NULL);
}
 
static void threadedTest() {
    pthread_t thread;
    pthread_attr_t attr;
 
 
    /* we take default status:
       - joinable
       - default contention scope  ??
       - default stack attributes
    */
    CHECKP(pthread_attr_init(&attr));
 
    /* always set this so that the thread uses the attr object we pass in */
    CHECKP(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED));
     
    CHECKP(pthread_create(&thread, &attr, threadRun, 0));
     
}
 
int main(int argc, char* argv[]) {
 
    if (argc > 1) {
        printf("Doing threaded test\n");
        threadedTest();
        pthread_exit(0);
    }
    else {
        printf("Doing normal test\n");
        test();
    }
    return 0;
}


Actual Results:  2. hyperT ~ > ./fcntlbug
Doing normal test
Managed to set up socket 3 ok

3. hyperT ~ > ./fcntlbug t
Doing threaded test
error fcntl(3, F_SETOWN, 28525): Operation not permitted


Expected Results:  3. hyperT ~ > ./fcntlbug t
Doing threaded test
Managed to set up socket 3 ok


Additional info:

Comment 1 Roland McGrath 2003-10-22 07:12:28 UTC
I have a draft kernel patch we will try out.

Comment 2 Bugzilla owner 2004-09-30 15:41:36 UTC
Thanks for the bug report. However, Red Hat no longer maintains this version of
the product. Please upgrade to the latest version and open a new bug if the problem
persists.

The Fedora Legacy project (http://fedoralegacy.org/) maintains some older releases, 
and if you believe this bug is interesting to them, please report the problem in
the bug tracker at: http://bugzilla.fedora.us/